package com.zaicheng.cloud.remotecall;

import com.zaicheng.cloud.Client;
import com.zaicheng.cloud.netty.RpcRequest;
import com.zaicheng.cloud.netty.client.NettyClient;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 @author zaicheng
 @version 1.0
 @date 2022-04-19
 @email zzc15847256473@163.com
 */

public abstract class RemoteCall {

    public RemoteCall() { }

    public static RemoteCall.Builder builder(){
        return new RemoteCall.Builder();
    };

    public static String configKey(Class targetType, Method method) {
        StringBuilder builder = new StringBuilder();
        builder.append(targetType.getSimpleName());
        builder.append('#').append(method.getName()).append('(');
        Type[] var3 = method.getGenericParameterTypes();
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Type param = var3[var5];
            param = Types.resolve(targetType, targetType, param);
            builder.append(Types.getRawType(param).getSimpleName()).append(',');
        }

        if (method.getParameterTypes().length > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }

        return builder.append(')').toString();
    }


    public abstract <T> T newInstance(Target<T> var1);

    public static class Builder{
        private final List<RequestInterceptor> requestInterceptors = new ArrayList();
        private Client client;
        private Contract contract;
        private RpcRequest.Options options;
        private InvocationHandlerFactory invocationHandlerFactory;
        private List<Capability> capabilities;

        public Builder() {
            this.contract = new Contract.Default();
            this.options = new RpcRequest.Options();
            this.invocationHandlerFactory = new InvocationHandlerFactory.Default();
            this.client = new NettyClient();
            this.capabilities = new ArrayList<>();
        }

        public  RemoteCall.Builder  client(Client client){
            this.client = client;
            return  this;
        }

        public  <T> T target(Class<T> type,String url){
            return this.target(new Target.RemoteCallTarget(type,url));
        }

        public  <T> T  target(Target target){
            return (T) this.build().newInstance(target);
        }

        public  RemoteCall  build(){

            Client client = new NettyClient();
            RpcRequest.Options options = new RpcRequest.Options();
            List<RequestInterceptor> requestInterceptors = (List)this.requestInterceptors.stream().map((ri) -> {
                return (RequestInterceptor)Capability.enrich(ri, this.capabilities);
            }).collect(Collectors.toList());
            InvocationHandlerFactory invocationHandlerFactory = new InvocationHandlerFactory.Default();
            Contract contract = (Contract)Capability.enrich(this.contract, this.capabilities);
            NettyMethodHandler.Factory synchronousMethodHandlerFactory = new NettyMethodHandler.Factory(client, requestInterceptors);
            ReflectiveRemoteCall.ParseHandlersByName parseHandlersByName = new ReflectiveRemoteCall.ParseHandlersByName(options,synchronousMethodHandlerFactory,contract);

            return new ReflectiveRemoteCall(invocationHandlerFactory, parseHandlersByName);
        }
    }
}
